﻿/*Copyright (c) 2012 Cesar Ramirez
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies or substantial 
 * portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MechTactics.GameElements;
using System.Xml;
using System.Text.RegularExpressions;

namespace MechTactics
{
    public static class Serializer
    {
        public static string fromStatstoString(int playerNumber, int startingOre, KeyValuePair<int, int> initialPosition, int maxTurn)
        {
            XmlDocument doc = new XmlDocument();

            XmlNode player = doc.CreateNode(XmlNodeType.Element, "player", "");

            XmlNode playerNum = doc.CreateNode(XmlNodeType.Element, "id", "");
            playerNum.InnerText = playerNumber.ToString();
            player.AppendChild(playerNum);

            XmlNode ore = doc.CreateNode(XmlNodeType.Element, "ore", "");
            ore.InnerText = startingOre.ToString();
            player.AppendChild(ore);

            XmlNode position = doc.CreateNode(XmlNodeType.Element, "InitXY", "");
            XmlNode player_x = doc.CreateNode(XmlNodeType.Element, "x", "");
            XmlNode player_y = doc.CreateNode(XmlNodeType.Element, "y", "");
            player_x.InnerText = initialPosition.Key.ToString();
            player_y.InnerText = initialPosition.Value.ToString();
            position.AppendChild(player_x);
            position.AppendChild(player_y);
            player.AppendChild(position);

            XmlNode maxTurnXml = doc.CreateNode(XmlNodeType.Element, "maxTurn", "");
            maxTurnXml.InnerText = maxTurn.ToString();
            player.AppendChild(maxTurnXml);

            doc.AppendChild(player);
            return doc.OuterXml;
        }

        public static string fromMapToString(TileMap map)
        {
            XmlDocument doc = new XmlDocument();                             
            XmlNode root = doc.CreateNode(XmlNodeType.Element, "map", "");    
            XmlNode landscapeLength = doc.CreateNode(XmlNodeType.Element, "length", "");
            landscapeLength.InnerText = map.size.ToString();
            root.AppendChild(landscapeLength);
            XmlNode terrain = doc.CreateNode(XmlNodeType.Element, "terrain", "");
            for (int i = 0; i < map.size; i++)                                   
            {
                for (int j = 0; j < map.size; j++)                                  
                {
                    Tile tile = map.terrain[i, j];          
                    XmlNode land = doc.CreateNode(XmlNodeType.Element, "tile", ""); 
                    XmlNode x = doc.CreateNode(XmlNodeType.Element, "x", "");       
                    x.InnerText = tile.x.ToString();                                
                    XmlNode y = doc.CreateNode(XmlNodeType.Element, "y", "");       
                    y.InnerText = tile.y.ToString();                                
                    XmlNode type = doc.CreateNode(XmlNodeType.Element, "type", ""); 
                    type.InnerText = tile.z.ToString();                          
                    land.AppendChild(x);                                            
                    land.AppendChild(y);
                    land.AppendChild(type);
                    terrain.AppendChild(land);                                    
                }
            }
            root.AppendChild(terrain);
            doc.AppendChild(root);
            return doc.OuterXml;
        }

        public static string fromElementsToString(List<GameObject> components, int ore)
        {
            XmlDocument doc = new XmlDocument();
            doc.AppendChild(doc.CreateNode(XmlNodeType.Element, "snapshot", ""));
            XmlNode root = doc.DocumentElement;

            XmlNode Ore = doc.CreateNode(XmlNodeType.Element, "ore", "");
            Ore.InnerText = ore.ToString();
            root.AppendChild(Ore);

            XmlNode enemies = doc.CreateNode(XmlNodeType.Element, "objects", "");
            foreach (GameObject e in components)
            {
                XmlNode gameObject = doc.CreateNode(XmlNodeType.Element, "object", "");
                XmlNode objectId = doc.CreateNode(XmlNodeType.Element, "objectId", "");
                XmlNode objectType = doc.CreateNode(XmlNodeType.Element, "objectType", "");
                XmlNode objectTeam = doc.CreateNode(XmlNodeType.Element, "objectTeam", "");
                XmlNode objectY = doc.CreateNode(XmlNodeType.Element, "objectY", "");
                XmlNode objectX = doc.CreateNode(XmlNodeType.Element, "objectX", "");
                objectId.InnerText = e.getId().ToString();
                objectType.InnerText = e.getType().ToString();
                objectTeam.InnerText = e.getTeam().ToString();
                objectY.InnerText = e.getY().ToString();
                objectX.InnerText = e.getX().ToString();
                gameObject.AppendChild(objectId);
                gameObject.AppendChild(objectType);
                gameObject.AppendChild(objectTeam);
                gameObject.AppendChild(objectX);
                gameObject.AppendChild(objectY);
                enemies.AppendChild(gameObject);
            }
            root.AppendChild(enemies);
            return root.OuterXml;
        }

        public static Command fromStringToCommand(string action)
        {
            Command command;
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(Regex.Replace(action, @"\p{C}+", ""));
                XmlElement root = doc.DocumentElement;
                int playerId = Int32.Parse(root.SelectSingleNode("playerId").InnerText);
                int objectId = Int32.Parse(root.SelectSingleNode("objectId").InnerText);
                char type = Char.Parse(root.SelectSingleNode("type").InnerText);
                string tempKVP = root.SelectSingleNode("objective").InnerText;
                int key = Int32.Parse(tempKVP.Split(',')[0].Substring(1));
                int value = Int32.Parse(tempKVP.Split(',')[1].Substring(0, tempKVP.Split(',')[1].Length - 1));
                KeyValuePair<int, int> objective = new KeyValuePair<int, int>(key, value);
                command = new Command(playerId, objectId, type, objective);
                return command;
            }
            catch (Exception e)
            {
                command = new Command();
                return command;
            }
        }

        public static List<Command> fromStringToCommandList(string action)
        {
            List<Command> commandList;
            try
            {
                commandList = new List<Command>(0);

                XmlDocument doc = new XmlDocument();
                doc.LoadXml(Regex.Replace(action, @"\p{C}+", ""));
                XmlElement root = doc.DocumentElement;
                
                foreach (XmlNode child in root.ChildNodes)
                {
                    Command command = fromStringToCommand(child.OuterXml);
                    commandList.Add(command);
                }
                            
                return commandList;
            }
            catch (Exception e)
            {
                commandList = new List<Command>(0);
                return commandList;
            }
        }

        public static string fromCommandToString(Command action)
        {
            XmlDocument doc = new XmlDocument();
            doc.AppendChild(doc.CreateNode(XmlNodeType.Element, "command", ""));
            XmlNode root = doc.DocumentElement;

            XmlNode xml_playerId = doc.CreateNode(XmlNodeType.Element, "playerId", "");
            xml_playerId.InnerText = action.playerId.ToString();
            root.AppendChild(xml_playerId);

            XmlNode xml_objectId = doc.CreateNode(XmlNodeType.Element, "objectId", "");
            xml_objectId.InnerText = action.objectId.ToString();
            root.AppendChild(xml_objectId);

            XmlNode xml_type = doc.CreateNode(XmlNodeType.Element, "type", "");
            xml_type.InnerText = action.type.ToString();
            root.AppendChild(xml_type);

            XmlNode xml_objective = doc.CreateNode(XmlNodeType.Element, "objective", "");
            xml_objective.InnerText = action.objective.ToString();
            root.AppendChild(xml_objective);

            return root.OuterXml;
        }

        public static string fromCommandListToString(List<Command> actionList)
        {
            XmlDocument doc = new XmlDocument();
            doc.AppendChild(doc.CreateNode(XmlNodeType.Element, "commandList", ""));
            XmlNode root = doc.DocumentElement;

            XmlDocument node = new XmlDocument();
            foreach (Command action in actionList)
            {
                string temp = fromCommandToString(action);
                doc.LoadXml(temp);

                XmlNode commandNode = doc.DocumentElement;
                root.AppendChild(commandNode);
            }

            return root.OuterXml;
        }

        public static Client fromStringToStats(string initData)
        {
            Client client;
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(Regex.Replace(initData, @"\p{C}+", ""));
                XmlElement root = doc.DocumentElement;
                int playerId = Int32.Parse(root.SelectSingleNode("id").InnerText);
                int ore = Int32.Parse(root.SelectSingleNode("ore").InnerText);
                XmlNode initxy = root.SelectSingleNode("InitXY");
                int key   = Int32.Parse(initxy.SelectSingleNode("x").InnerText);
                int value = Int32.Parse(initxy.SelectSingleNode("y").InnerText);
                KeyValuePair<int, int> position = new KeyValuePair<int, int>(key, value);
                client = new Client(playerId);
                client.Player.setInitialParams(position, ore, null);
                return client;
            }
            catch (Exception e)
            {
                client = new Client();
                return client;
            }
        }

        public static TileMap fromStringToMap(string mapData)
        {
            TileMap map;
            try
            {
                int[,] _map;
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(Regex.Replace(mapData, @"\p{C}+", ""));
                XmlElement root = doc.DocumentElement;

                int length = Int32.Parse(root.SelectSingleNode("length").InnerText);
                
                _map = new int[length,length];

                XmlNode terrain = root.SelectSingleNode("terrain");
                foreach (XmlNode child in terrain.ChildNodes)
                {
                    int x = Int32.Parse(child.SelectSingleNode("x").InnerText);
                    int y = Int32.Parse(child.SelectSingleNode("y").InnerText);
                    int z = Int32.Parse(child.SelectSingleNode("type").InnerText);
                    _map[x, y] = z;
                }

                map = new TileMap(_map);
                return map;
            }
            catch (Exception e)
            {
                map = new TileMap();
                return map;
            }
        }

        /*public static int fromStringToMapMaxHeight(string mapData)
        {
            int length = 0;
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(Regex.Replace(mapData, @"\p{C}+", ""));
                XmlElement root = doc.DocumentElement;
                length = Int32.Parse(root.SelectSingleNode("length").InnerText);
                return length;
            }
            catch (Exception e)
            {
                return length;
            }
        }*/
    }
}
